#include <windows.h>
#include <GL/glut.h>
#include <cmath>
#include <cstdio>

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

bool mouseIsDown = false;
int mx, my;
float rx = 30.0f;
float ry = 45.0f;

GLuint appleTextureID = 0;

GLfloat light_pos[] = {0.0f, 1.0f, 1.0f, 1.0f};
GLfloat ground_plane[] = {0.0f, 1.0f, 0.0f, 0.0f};

GLuint LoadTexture(const char *filename)
{
    GLuint texture;
    int width, height;
    unsigned char *data;

    FILE *file = fopen(filename, "rb");
    if (file == NULL) return 0;

    unsigned char header[54];
    if (fread(header, 54, 1, file) != 1) {
        fclose(file);
        return 0;
    }

    width = *(int *)&(header[18]);
    height = *(int *)&(header[22]);

    int size = width * height * 3;
    data = new unsigned char[size];

    fread(data, size, 1, file);
    fclose(file);

    for (int i = 0; i < size; i += 3)
    {
        unsigned char b = data[i];
        data[i] = data[i + 2];
        data[i + 2] = b;
    }

    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);

    delete[] data;
    return texture;
}

void drawLeaf()
{
    GLfloat leaf_color[] = {0.1f, 0.6f, 0.15f, 0.7f};
    GLfloat leaf_specular[] = {0.1f, 0.1f, 0.1f, 1.0f};
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, leaf_color);
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, leaf_specular);

    glPushMatrix();
    glScalef(0.4, 0.4, 0.4);
    glBegin(GL_TRIANGLES);
        glNormal3f(0.0f, 1.0f, 0.3f);
        glVertex3f(0.0f, 0.0f, 0.0f);
        glVertex3f(0.5f, 0.1f, 0.5f);
        glVertex3f(0.0f, 0.0f, 1.2f);
        glNormal3f(0.0f, 1.0f, 0.3f);
        glVertex3f(0.0f, 0.0f, 0.0f);
        glVertex3f(-0.5f, 0.1f, 0.5f);
        glVertex3f(0.0f, 0.0f, 1.2f);
    glEnd();
    glPopMatrix();
}

void drawSolidApple(int slices, int stacks)
{
    GLfloat apple_color[] = {1.0f, 1.0f, 1.0f, 1.0f};
    GLfloat apple_specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
    GLfloat apple_shininess[] = {120.0f};

    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, apple_color);
    glMaterialfv(GL_FRONT, GL_SPECULAR, apple_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, apple_shininess);

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, appleTextureID);

    float R = 0.5f;
    float min_bottom_radius = 0.14f;
    float squash = 0.8f; // y方向整体缩短

    // 计算顶部凹陷边缘的y值（theta = M_PI * 0.08）
    float theta_top_edge = M_PI * 0.08;
    float r_top_edge = R * (0.8f + 0.2f * sin(theta_top_edge));
    float y_top_edge = R * (cos(theta_top_edge) + 0.2f * pow(sin(theta_top_edge), 2) - 0.1f);
    y_top_edge -= 0.12f * sin(1.0f * M_PI / 2); // 顶部凹陷深度
    y_top_edge *= squash;
    float stem_leaf_offset = 0.06f; // 叶柄和叶子整体再往上移动的距离

    for (int i = 0; i < stacks; i++) {
        float v1 = (float)i / stacks;
        float v2 = (float)(i + 1) / stacks;
        float theta1 = v1 * M_PI;
        float theta2 = v2 * M_PI;

        glBegin(GL_QUAD_STRIP);
        for (int j = 0; j <= slices; j++) {
            float u = (float)j / slices;
            float phi = u * 2.0f * M_PI;

            float r1 = R * (0.8f + 0.2f * sin(theta1));
            float r2 = R * (0.8f + 0.2f * sin(theta2));

            float y1 = R * (cos(theta1) + 0.2f * pow(sin(theta1), 2) - 0.1f);
            float y2 = R * (cos(theta2) + 0.2f * pow(sin(theta2), 2) - 0.1f);

            // 下半部分增胖
            if (theta1 > M_PI / 2) {
                float t = (theta1 - M_PI / 2) / (M_PI / 2); // 0~1
                r1 *= (1.0f + 0.27f * pow(t, 1.5f)); // 0.25f 越大越胖
            }
            if (theta2 > M_PI / 2) {
                float t = (theta2 - M_PI / 2) / (M_PI / 2);
                r2 *= (1.0f + 0.25f * pow(t, 1.5f));
            }

            // 顶部凹陷
            if (theta1 < M_PI * 0.08) {
                float t = (M_PI * 0.08 - theta1) / (M_PI * 0.08);
                y1 -= 0.12f * sin(t * M_PI / 2);
                r1 *= (1.0f - 0.25f * t);
            }
            if (theta2 < M_PI * 0.08) {
                float t = (M_PI * 0.08 - theta2) / (M_PI * 0.08);
                y2 -= 0.12f * sin(t * M_PI / 2);
                r2 *= (1.0f - 0.25f * t);
            }
            // 底部凹陷（与顶部完全对称）
            if (theta1 > M_PI * 0.92) {
                float t = (theta1 - M_PI * 0.92) / (M_PI * 0.08);
                y1 += 0.12f * sin(t * M_PI / 2);
                r1 *= (1.0f - 0.25f * t);
            }
            if (theta2 > M_PI * 0.92) {
                float t = (theta2 - M_PI * 0.92) / (M_PI * 0.08);
                y2 += 0.12f * sin(t * M_PI / 2);
                r2 *= (1.0f - 0.25f * t);
            }
            // 底部收口
            if (theta1 > M_PI * 0.99) {
                r1 *= 0.3f;
            }
            if (theta2 > M_PI * 0.99) {
                r2 *= 0.3f;
            }

            // 主体整体缩短
            y1 *= squash;
            y2 *= squash;

            float x1 = r1 * cos(phi) * sin(theta1);
            float z1 = r1 * sin(phi) * sin(theta1);
            glNormal3f(x1, y1, z1);
            glTexCoord2f(u, v1);
            glVertex3f(x1, y1, z1);

            float x2 = r2 * cos(phi) * sin(theta2);
            float z2 = r2 * sin(phi) * sin(theta2);
            glNormal3f(x2, y2, z2);
            glTexCoord2f(u, v2);
            glVertex3f(x2, y2, z2);
        }
        glEnd();
    }
    glDisable(GL_TEXTURE_2D);

    // --- 2. 叶柄 ---
    GLfloat stem_color[] = {0.4f, 0.25f, 0.1f, 1.0f};
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, stem_color);

    glPushMatrix();
    glTranslatef(0, y_top_edge + stem_leaf_offset, 0);
    glRotatef(20, 1, 0, 0);
    GLUquadric *quad = gluNewQuadric();
    gluCylinder(quad, 0.02, 0.015, 0.15, 12, 1);
    gluDeleteQuadric(quad);
    glPopMatrix();

    // --- 3. 叶子 ---
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glPushMatrix();
    glTranslatef(0, y_top_edge + stem_leaf_offset, 0.02f);
    glRotatef(50, 0, 1, 0);
    glRotatef(-30, 1, 0, 0);
    drawLeaf();
    glPopMatrix();
    glDisable(GL_BLEND);
}

void drawGround()
{
    GLfloat ground_color[] = {0.8f, 0.8f, 0.8f, 1.0f};
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ground_color);

    glBegin(GL_QUADS);
        glNormal3f(0, 1, 0);
        glVertex3f(-2, -0.75f, -2); // 下移
        glVertex3f(-2, -0.75f,  2);
        glVertex3f( 2, -0.75f,  2);
        glVertex3f( 2, -0.75f, -2);
    glEnd();
}

void drawShadow()
{
    GLfloat shadow_matrix[16];
    float dot = ground_plane[0] * light_pos[0] +
                ground_plane[1] * light_pos[1] +
                ground_plane[2] * light_pos[2] +
                ground_plane[3] * light_pos[3];

    for(int j=0; j<4; ++j) {
        for(int i=0; i<4; ++i) {
            shadow_matrix[j*4+i] = (j==i) * dot - light_pos[i] * ground_plane[j];
        }
    }

    glPushMatrix();
    glDisable(GL_LIGHTING);
    glDisable(GL_TEXTURE_2D);
    glColor4f(0.1f, 0.1f, 0.1f, 0.6f);

    glTranslatef(0, -0.74f, 0); // 下移
    glMultMatrixf(shadow_matrix);

    drawSolidApple(20, 20);

    glEnable(GL_LIGHTING);
    glPopMatrix();
}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(0.0f, 0.0f, -2.5f);

    glRotatef(rx, 1.0f, 0.0f, 0.0f);
    glRotatef(ry, 0.0f, 1.0f, 0.0f);

    // 可视化光源
    glPushMatrix();
    glDisable(GL_LIGHTING); // 让光源球体自身不受光照影响
    glColor3f(1.0f, 1.0f, 0.0f); // 黄色
    glTranslatef(light_pos[0], light_pos[1], light_pos[2]);
    glutSolidSphere(0.06, 16, 16); 
    glEnable(GL_LIGHTING);
    glPopMatrix();

    drawGround();
    drawShadow();
    drawSolidApple(50, 50);

    glutSwapBuffers();
}

void reshape(int w, int h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (h == 0) h = 1;
    gluPerspective(45.0f, (float)w / (float)h, 0.1f, 100.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void mouse(int button, int state, int x, int y)
{
    if (button == GLUT_LEFT_BUTTON) {
        if (state == GLUT_DOWN) {
            mouseIsDown = true;
            mx = x;
            my = y;
        } else {
            mouseIsDown = false;
        }
    }
}

void motion(int x, int y)
{
    if (mouseIsDown) {
        ry += (x - mx);
        rx += (y - my);
        mx = x;
        my = y;
        glutPostRedisplay();
    }
}

void special(int key, int x, int y)
{
    switch (key) {
    case GLUT_KEY_UP:    rx -= 5.0f; break;
    case GLUT_KEY_DOWN:  rx += 5.0f; break;
    case GLUT_KEY_LEFT:  ry -= 5.0f; break;
    case GLUT_KEY_RIGHT: ry += 5.0f; break;
    }
    glutPostRedisplay();
}

void init()
{
    glClearColor(0.9f, 0.9f, 1.0f, 1.0f);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_NORMALIZE);
    glShadeModel(GL_SMOOTH);

    appleTextureID = LoadTexture("apple_texture.bmp");
    if (appleTextureID == 0) {
        printf("Error: Failed to load texture 'apple_texture.bmp'.\n");
        printf("Please make sure a 24-bit BMP file with this name is in the same directory.\n");
    }

    GLfloat ambient[] = {0.3f, 0.3f, 0.3f, 1.0f};
    GLfloat diffuse[] = {0.9f, 0.9f, 0.9f, 1.0f};
    GLfloat specular[] = {1.0f, 1.0f, 1.0f, 1.0f};

    glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
}

int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 800);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Apple 3D Rendering with Advanced Effects");

    init();

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutSpecialFunc(special);

    glutMainLoop();
    return 0;
}
